第一阶段:基础核心

基础类型 (Basic Types)

基础类型是构建所有更复杂类型的基础

数组 (Arrays)、元组 (Tuples)

函数 (Functions)

为函数的参数返回值提供类型定义

function foo(a: number, b?: string): string {
    return `${a}${b}`
}

const bar: (a: number, b?: string) => void = (a, b) => {}

为你写的每一个函数都添加类型

对象、接口 (Interfaces)、类型别名 (Type Aliases)

接口和类型别名都可以描述对象结构,但有细微差别和侧重点

第二阶段:进阶概念

联合类型 (Union Types)、交叉类型 (Intersection Types)

类型断言 (Type Assertions)、类型守卫 (Type Guards)

字面量类型 (Literal Types)、枚举 (Enums)

类 (Classes)

TypeScript 对 ES6 class 的增强,加入了类型注解和访问修饰符

访问修饰符:

在使用面向对象编程(OOP)范式来组织代码时,class 是核心

第三阶段:高级与泛型

泛型 (Generics)

泛型是 TypeScript 的一个核心特性,它允许编写可重用的组件。可以把它想象成一个类型的"占位符"或"变量",在使用它时才传入具体的类型

要解决的问题:避免为不同类型重复编写相同的逻辑,同时又不像 any 那样丢失类型信息

// 尝试 1: 使用 any,丢失了类型信息
function identityAny(arg: any): any {
    return arg;
}
const outputAny = identityAny("hello"); // outputAny 的类型是 any

// 解决方案: 使用泛型
function identity<T>(arg: T): T {
	return arg;
}
const output = identity("hello"); // output 的类型被正确推断为 string

核心场景

// 场景:创建一个函数,它的输入和输出类型可以根据调用时传入的类型动态确定
function createSuccessResponse<T>(data: T) {
	return { success: true, data: data };
}
const userResponse = createSuccessResponse({ id: 1, name: "Alice" });
// userResponse.data.id 具有正确的类型提示
// 场景:定义一个分页查询的返回结果,其中列表项的类型是可变的
interface PaginatedResult<T> {
	items: T[];
	total: number;
}
// 场景:确保传入的参数一定有 .length 属性
function logLength<T extends { length: number }>(arg: T): void {
    console.log(arg.length);
}

logLength("hello"); // OK
logLength(123);     // Error

高级类型 (Advanced Types)

这些类型工具可以让你对已有类型进行变换、组合和提取

keyof

获取一个类型的所有,并返回一个由这些键组成的字符串字面量联合类型

function getProperty<T, K extends keyof T>(obj: T, key: K) {
	return obj[key]; // key 被约束为 obj 中存在的键
}

typeof

在类型上下文中,获取一个变量或属性的类型

场景:想从一个已存在的 JavaScript 对象中创建类型,而不想手动重复定义时

const AppConfig = { apiPrefix: "/api", maxRetries: 3 };
type Config = typeof AppConfig; // { apiPrefix: string; maxRetries: number; }

映射类型 (Mapped Types)

基于一个已有的类型,通过规则转换它的每一个属性,从而创建一个新类型

语法:[P in K]: T,类似 for...in 循环

示例(实现 Readonly):

type MyReadonly<T> = {
	readonly [P in keyof T]: T[P];
};

条件类型 (Conditional Types)

让类型根据一个条件在两种类型中选择一种

语法:SomeType extends OtherType ? TrueType : FalseType;

infer 关键字:在 extends 条件中,可以捕获推断出的类型

示例(解包数组元素的类型):

type Flatten<T> = T extends (infer I)[] ? I : T;
type Str = Flatten<string[]>; // string
type Num = Flatten<number>;   // number

工具类型 (Utility Types)

TypeScript 内置了很多方便的、基于泛型和高级类型实现的工具类型,可以直接使用,极大地提高开发效率

Partial<T>

让属性都变成可选的

type A = { a: number; b: string; }
type A1 = Partial<A> // { a?: number; b?: string; }

Required<T>

让属性都变成必选

type A = { a?: number; b?: string; }
type A1 = Required<A> // { a: number; b: string; }

Pick<T, K>

保留选择的属性,K 代表要保留的属性键值

type A = { a: number; b: string; c: boolean }
type A1 = Pick<A, 'a' | 'b'> // { a: number; b: string; }

Omit<T, K>

排除选择的属性,K 代表要排除的属性键值

type A = { a: number; b: string; }
type A1 = Omit<A, 'a'> // { b: string }

Record<K, V>

K 代表键值的类型,V 代表值的类型

type A = Record<string, number> // 等价 { [k: string]: number }

Exclude<T, U>

过滤 T 中和 U 相同(或兼容)的类型

type A1 = Exclude<number | string, string | number[]> // number

// 兼容
type A2 = Exclude<number | string, any> // never, 因为 any 兼容任何类型

Extract<T, U>

提取 T 中和 U 相同(或兼容)的类型

type A1 = Extract<number | string, string | number[]> // string

NonNullable<T>

剔除 T 中的 undefinednull

type A1 = NonNullable<number | string | null | undefined> // number | string

Parameters<T>

获取函数类型 T 的参数类型,返回类型为元祖,元素顺序同参数顺序

type A1 = Parameters<(a: number, b: string) => void> // [number, string]

ReturnType<T>

获取函数类型 T 的返回值的类型

type A1 = ReturnType<() => number> // number

InstanceType<T>

T 如果是构造函数类型,那么 InstanceType 可以返回他的实例类型

interface A {
    a: HTMLElement;
}

interface AConstructor {
    new(): A;
}

function create(AClass: AConstructor): InstanceType<AConstructor> {
    return new AClass();
}

ConstructorParameters<T>

获取构造函数 T 的参数类型,和 Parameters<T> 类似,只是这里 T 是构造函数类型

interface AConstructor {
    new(a: number): string[];
}

type A1 = ConstructorParameters<AConstructor> // number

第四阶段:工程实践

模块化 (Modules)

TypeScript 遵循 ES6 模块标准,使用 importexport 来组织代码结构。在任何非 "Hello World" 的项目中,都应该使用模块化来拆分代码,保持代码的清晰和可维护性

声明文件 (Declaration Files)

后缀为 .d.ts 的文件,它不包含实现,只包含类型定义

场景:使用一个纯 JavaScript 编写的库时,它本身没有类型信息。为了在 TypeScript 项目中获得这个库的类型检查和智能提示,需要为其提供一个声明文件。很多流行的库都有社区维护的 @types/... 包,可以直接安装

tsconfig.json 解析

TypeScript 编译器的配置文件,它告诉编译器如何检查和编译你的代码

重要选项: